[lld] [lld][WebAssembly] Add `--no-growable-memory` (PR #82890)

via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 25 01:18:43 PST 2024


https://github.com/SingleAccretion updated https://github.com/llvm/llvm-project/pull/82890

>From 5f52f345a1e18b1b26b178a3a5dd576d7c7cff9c Mon Sep 17 00:00:00 2001
From: SingleAccretion <AccretionMail at yandex.ru>
Date: Sat, 24 Feb 2024 19:51:06 +0300
Subject: [PATCH 1/3] [lld][WebAssembly] Add "--max-memory-growth"

With this option, clients (Emscripten) can implement non-growable
memories without knowing the amount of initial memory upfront.
---
 lld/docs/WebAssembly.rst        |  4 +++
 lld/test/wasm/data-layout.s     | 32 ++++++++++++++++++++++++
 lld/test/wasm/large-memory.test |  8 ++++++
 lld/wasm/Config.h               |  1 +
 lld/wasm/Driver.cpp             |  1 +
 lld/wasm/Options.td             |  3 +++
 lld/wasm/Writer.cpp             | 44 ++++++++++++++++++++++++---------
 7 files changed, 81 insertions(+), 12 deletions(-)

diff --git a/lld/docs/WebAssembly.rst b/lld/docs/WebAssembly.rst
index 3f554de46d38a7..ede78309ecfb1e 100644
--- a/lld/docs/WebAssembly.rst
+++ b/lld/docs/WebAssembly.rst
@@ -131,6 +131,10 @@ WebAssembly-specific options:
 
   Initial size of the linear memory. Default: the sum of stack, static data and heap sizes.
 
+.. option:: --max-memory-growth=<value>
+
+  Maximum size of memory that can be allocated dynamically. Default: unlimited.
+
 .. option:: --max-memory=<value>
 
   Maximum size of the linear memory. Default: unlimited.
diff --git a/lld/test/wasm/data-layout.s b/lld/test/wasm/data-layout.s
index 2a447aad622167..6e6a6cde747e2f 100644
--- a/lld/test/wasm/data-layout.s
+++ b/lld/test/wasm/data-layout.s
@@ -103,6 +103,38 @@ local_struct_internal_ptr:
 # CHECK-MAX-NEXT:         Minimum:         0x2
 # CHECK-MAX-NEXT:         Maximum:         0x2
 
+# RUN: wasm-ld --no-entry --initial-memory=327680 --max-memory-growth=0 \
+# RUN:     -o %t_max.wasm %t.hello32.o
+# RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX-GROWTH-ZERO
+
+# CHECK-MAX-GROWTH-ZERO:        - Type:            MEMORY
+# CHECK-MAX-GROWTH-ZERO-NEXT:     Memories:
+# CHECK-MAX-GROWTH-ZERO:           - Flags:           [ HAS_MAX ]
+# CHECK-MAX-GROWTH-ZERO:             Minimum:         0x5
+# CHECK-MAX-GROWTH-ZERO:             Maximum:         0x5
+
+# RUN: wasm-ld --initial-memory=196608 --max-memory-growth=262144 \
+# RUN:     --no-entry -o %t_max.wasm %t.hello32.o
+# RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX-GROWTH-SOME
+
+# CHECK-MAX-GROWTH-SOME:        - Type:            MEMORY
+# CHECK-MAX-GROWTH-SOME-NEXT:     Memories:
+# CHECK-MAX-GROWTH-SOME:           - Flags:           [ HAS_MAX ]
+# CHECK-MAX-GROWTH-SOME:             Minimum:         0x3
+# CHECK-MAX-GROWTH-SOME:             Maximum:         0x7
+
+# RUN: not wasm-ld --max-memory-growth=131073 \
+# RUN:     --no-entry -o %t_max.wasm %t.hello32.o 2>&1 \
+# RUN: | FileCheck %s --check-prefix CHECK-MAX-GROWTH-ALIGN-ERROR
+
+# CHECK-MAX-GROWTH-ALIGN-ERROR: maximum memory growth must be 65536-byte aligned
+
+# RUN: not wasm-ld --initial-memory=131072 --max-memory=262144 --max-memory-growth=131072 \
+# RUN:     --no-entry -o %t_max.wasm %t.hello32.o 2>&1 \
+# RUN: | FileCheck %s --check-prefix CHECK-MAX-GROWTH-COMPAT-ERROR
+
+# CHECK-MAX-GROWTH-COMPAT-ERROR: --max-memory-growth and --max-memory are mutually exclusive
+
 # RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry --shared-memory \
 # RUN:     --features=atomics,bulk-memory --initial-memory=131072 \
 # RUN:     --max-memory=131072 -o %t_max.wasm %t32.o %t.hello32.o
diff --git a/lld/test/wasm/large-memory.test b/lld/test/wasm/large-memory.test
index 5b737e41549630..bc39a65bb3311b 100644
--- a/lld/test/wasm/large-memory.test
+++ b/lld/test/wasm/large-memory.test
@@ -5,10 +5,16 @@ RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/start.s -o %
 RUN: wasm-ld %t.o -o %t1.wasm --max-memory=2147483648
 RUN: obj2yaml %t1.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-2G
 
+RUN: wasm-ld %t.o -o %t1.wasm --initial-memory=131072 --max-memory-growth=2147352576
+RUN: obj2yaml %t1.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-2G
+
 ; And also 4G of total memory
 RUN: wasm-ld %t.o -o %t2.wasm --max-memory=4294967296
 RUN: obj2yaml %t2.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-4G
 
+RUN: wasm-ld %t.o -o %t2.wasm --initial-memory=131072 --max-memory-growth=4294836224
+RUN: obj2yaml %t2.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-4G
+
 CHECK:      - Type:            MEMORY
 CHECK-NEXT:   Memories:
 CHECK-NEXT:     - Flags:           [ HAS_MAX ]
@@ -19,6 +25,8 @@ CHECK-4G-NEXT:    Maximum:         0x10000
 ; Test error for more than 4G of memory
 RUN: not wasm-ld %t.o -o %t3.wasm --initial-memory=4295032832 2>&1 | FileCheck %s --check-prefix INIT-ERROR
 RUN: not wasm-ld %t.o -o %t4.wasm --max-memory=4295032832 2>&1 | FileCheck %s --check-prefix MAX-ERROR
+RUN: not wasm-ld %t.o -o %t4.wasm --initial-memory=131072 --max-memory-growth=4294901760 2>&1 | FileCheck %s --check-prefix MAX-GROWTH-ERROR
 
 INIT-ERROR: initial memory too large, cannot be greater than 4294967296
 MAX-ERROR: maximum memory too large, cannot be greater than 4294967296
+MAX-GROWTH-ERROR: maximum memory growth too large, cannot be greater than 4294836224
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 97c508bda6a1c3..70872685b40120 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -77,6 +77,7 @@ struct Configuration {
   uint64_t globalBase;
   uint64_t initialHeap;
   uint64_t initialMemory;
+  uint64_t maxMemoryGrowth;
   uint64_t maxMemory;
   // The table offset at which to place function addresses.  We reserve zero
   // for the null function pointer.  This gets set to 1 for executables and 0
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 635f19f78b15e6..87afdd223a707a 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -541,6 +541,7 @@ static void readConfigs(opt::InputArgList &args) {
   config->globalBase = args::getInteger(args, OPT_global_base, 0);
   config->initialHeap = args::getInteger(args, OPT_initial_heap, 0);
   config->initialMemory = args::getInteger(args, OPT_initial_memory, 0);
+  config->maxMemoryGrowth = args::getInteger(args, OPT_max_memory_growth, -1);
   config->maxMemory = args::getInteger(args, OPT_max_memory, 0);
   config->zStackSize =
       args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td
index 8190717cef63bb..ed3e014850278a 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -227,6 +227,9 @@ def initial_heap: JJ<"initial-heap=">,
 def initial_memory: JJ<"initial-memory=">,
   HelpText<"Initial size of the linear memory">;
 
+def max_memory_growth: JJ<"max-memory-growth=">,
+  HelpText<"Maximum size of dynamically allocatable linear memory">;
+
 def max_memory: JJ<"max-memory=">,
   HelpText<"Maximum size of the linear memory">;
 
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index d1a06c9ac9c2ae..261d633f11b745 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -473,6 +473,25 @@ void Writer::layoutMemory() {
     WasmSym::heapEnd->setVA(memoryPtr);
   }
 
+  if (config->maxMemory != 0 && config->maxMemoryGrowth != -1) {
+    // Erroring out here is simpler than defining precedence rules.
+    error("--max-memory-growth and --max-memory are mutually exclusive");
+  }
+
+  uint64_t maxMemory = 0;
+  if (config->maxMemoryGrowth != -1) {
+    if (config->maxMemoryGrowth !=
+        alignTo(config->maxMemoryGrowth, WasmPageSize))
+      error("maximum memory growth must be " + Twine(WasmPageSize) +
+            "-byte aligned");
+    uint64_t maxMaxMemoryGrowth = maxMemorySetting - memoryPtr;
+    if (config->maxMemoryGrowth > maxMaxMemoryGrowth)
+      error("maximum memory growth too large, cannot be greater than " +
+            Twine(maxMaxMemoryGrowth));
+
+    maxMemory = memoryPtr + config->maxMemoryGrowth;
+  }
+
   if (config->maxMemory != 0) {
     if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize))
       error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
@@ -481,20 +500,21 @@ void Writer::layoutMemory() {
     if (config->maxMemory > maxMemorySetting)
       error("maximum memory too large, cannot be greater than " +
             Twine(maxMemorySetting));
+
+    maxMemory = config->maxMemory;
   }
 
-  // Check max if explicitly supplied or required by shared memory
-  if (config->maxMemory != 0 || config->sharedMemory) {
-    uint64_t max = config->maxMemory;
-    if (max == 0) {
-      // If no maxMemory config was supplied but we are building with
-      // shared memory, we need to pick a sensible upper limit.
-      if (ctx.isPic)
-        max = maxMemorySetting;
-      else
-        max = memoryPtr;
-    }
-    out.memorySec->maxMemoryPages = max / WasmPageSize;
+  // If no maxMemory config was supplied but we are building with
+  // shared memory, we need to pick a sensible upper limit.
+  if (config->sharedMemory && maxMemory == 0) {
+    if (ctx.isPic)
+      maxMemory = maxMemorySetting;
+    else
+      maxMemory = memoryPtr;
+  }
+
+  if (maxMemory != 0) {
+    out.memorySec->maxMemoryPages = maxMemory / WasmPageSize;
     log("mem: max pages   = " + Twine(out.memorySec->maxMemoryPages));
   }
 }

>From 9bf7075d788ad3c8dbb664976f376450c299a8b9 Mon Sep 17 00:00:00 2001
From: SingleAccretion <AccretionMail at yandex.ru>
Date: Sun, 25 Feb 2024 00:18:34 +0300
Subject: [PATCH 2/3] Add --no-growable-memory instead

---
 lld/docs/WebAssembly.rst        |  8 ++++----
 lld/test/wasm/data-layout.s     | 36 +++++++++------------------------
 lld/test/wasm/large-memory.test |  8 --------
 lld/wasm/Config.h               |  2 +-
 lld/wasm/Driver.cpp             |  2 +-
 lld/wasm/Options.td             |  6 +++---
 lld/wasm/Writer.cpp             | 19 ++++-------------
 7 files changed, 23 insertions(+), 58 deletions(-)

diff --git a/lld/docs/WebAssembly.rst b/lld/docs/WebAssembly.rst
index ede78309ecfb1e..1dd05d67983c7d 100644
--- a/lld/docs/WebAssembly.rst
+++ b/lld/docs/WebAssembly.rst
@@ -131,14 +131,14 @@ WebAssembly-specific options:
 
   Initial size of the linear memory. Default: the sum of stack, static data and heap sizes.
 
-.. option:: --max-memory-growth=<value>
-
-  Maximum size of memory that can be allocated dynamically. Default: unlimited.
-
 .. option:: --max-memory=<value>
 
   Maximum size of the linear memory. Default: unlimited.
 
+.. option:: --no-growable-memory
+
+  Set maximum size of the linear memory to its initial size, disallowing memory growth.
+
 By default the function table is neither imported nor exported, but defined
 for internal use only.
 
diff --git a/lld/test/wasm/data-layout.s b/lld/test/wasm/data-layout.s
index 6e6a6cde747e2f..7f9da2e5387cac 100644
--- a/lld/test/wasm/data-layout.s
+++ b/lld/test/wasm/data-layout.s
@@ -103,37 +103,21 @@ local_struct_internal_ptr:
 # CHECK-MAX-NEXT:         Minimum:         0x2
 # CHECK-MAX-NEXT:         Maximum:         0x2
 
-# RUN: wasm-ld --no-entry --initial-memory=327680 --max-memory-growth=0 \
+# RUN: wasm-ld --no-entry --initial-memory=327680 --no-growable-memory \
 # RUN:     -o %t_max.wasm %t.hello32.o
-# RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX-GROWTH-ZERO
+# RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-NO-GROWTH
 
-# CHECK-MAX-GROWTH-ZERO:        - Type:            MEMORY
-# CHECK-MAX-GROWTH-ZERO-NEXT:     Memories:
-# CHECK-MAX-GROWTH-ZERO:           - Flags:           [ HAS_MAX ]
-# CHECK-MAX-GROWTH-ZERO:             Minimum:         0x5
-# CHECK-MAX-GROWTH-ZERO:             Maximum:         0x5
+# CHECK-NO-GROWTH:        - Type:            MEMORY
+# CHECK-NO-GROWTH-NEXT:     Memories:
+# CHECK-NO-GROWTH-NEXT:       - Flags:           [ HAS_MAX ]
+# CHECK-NO-GROWTH-NEXT:         Minimum:         0x5
+# CHECK-NO-GROWTH-NEXT:         Maximum:         0x5
 
-# RUN: wasm-ld --initial-memory=196608 --max-memory-growth=262144 \
-# RUN:     --no-entry -o %t_max.wasm %t.hello32.o
-# RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX-GROWTH-SOME
-
-# CHECK-MAX-GROWTH-SOME:        - Type:            MEMORY
-# CHECK-MAX-GROWTH-SOME-NEXT:     Memories:
-# CHECK-MAX-GROWTH-SOME:           - Flags:           [ HAS_MAX ]
-# CHECK-MAX-GROWTH-SOME:             Minimum:         0x3
-# CHECK-MAX-GROWTH-SOME:             Maximum:         0x7
-
-# RUN: not wasm-ld --max-memory-growth=131073 \
-# RUN:     --no-entry -o %t_max.wasm %t.hello32.o 2>&1 \
-# RUN: | FileCheck %s --check-prefix CHECK-MAX-GROWTH-ALIGN-ERROR
-
-# CHECK-MAX-GROWTH-ALIGN-ERROR: maximum memory growth must be 65536-byte aligned
-
-# RUN: not wasm-ld --initial-memory=131072 --max-memory=262144 --max-memory-growth=131072 \
+# RUN: not wasm-ld --max-memory=262144 --no-growable-memory \
 # RUN:     --no-entry -o %t_max.wasm %t.hello32.o 2>&1 \
-# RUN: | FileCheck %s --check-prefix CHECK-MAX-GROWTH-COMPAT-ERROR
+# RUN: | FileCheck %s --check-prefix CHECK-NO-GROWTH-COMPAT-ERROR
 
-# CHECK-MAX-GROWTH-COMPAT-ERROR: --max-memory-growth and --max-memory are mutually exclusive
+# CHECK-NO-GROWTH-COMPAT-ERROR: --max-memory and --no-growable-memory are mutually exclusive
 
 # RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry --shared-memory \
 # RUN:     --features=atomics,bulk-memory --initial-memory=131072 \
diff --git a/lld/test/wasm/large-memory.test b/lld/test/wasm/large-memory.test
index bc39a65bb3311b..5b737e41549630 100644
--- a/lld/test/wasm/large-memory.test
+++ b/lld/test/wasm/large-memory.test
@@ -5,16 +5,10 @@ RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/start.s -o %
 RUN: wasm-ld %t.o -o %t1.wasm --max-memory=2147483648
 RUN: obj2yaml %t1.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-2G
 
-RUN: wasm-ld %t.o -o %t1.wasm --initial-memory=131072 --max-memory-growth=2147352576
-RUN: obj2yaml %t1.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-2G
-
 ; And also 4G of total memory
 RUN: wasm-ld %t.o -o %t2.wasm --max-memory=4294967296
 RUN: obj2yaml %t2.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-4G
 
-RUN: wasm-ld %t.o -o %t2.wasm --initial-memory=131072 --max-memory-growth=4294836224
-RUN: obj2yaml %t2.wasm | FileCheck %s --check-prefixes=CHECK,CHECK-4G
-
 CHECK:      - Type:            MEMORY
 CHECK-NEXT:   Memories:
 CHECK-NEXT:     - Flags:           [ HAS_MAX ]
@@ -25,8 +19,6 @@ CHECK-4G-NEXT:    Maximum:         0x10000
 ; Test error for more than 4G of memory
 RUN: not wasm-ld %t.o -o %t3.wasm --initial-memory=4295032832 2>&1 | FileCheck %s --check-prefix INIT-ERROR
 RUN: not wasm-ld %t.o -o %t4.wasm --max-memory=4295032832 2>&1 | FileCheck %s --check-prefix MAX-ERROR
-RUN: not wasm-ld %t.o -o %t4.wasm --initial-memory=131072 --max-memory-growth=4294901760 2>&1 | FileCheck %s --check-prefix MAX-GROWTH-ERROR
 
 INIT-ERROR: initial memory too large, cannot be greater than 4294967296
 MAX-ERROR: maximum memory too large, cannot be greater than 4294967296
-MAX-GROWTH-ERROR: maximum memory growth too large, cannot be greater than 4294836224
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 70872685b40120..266348fef40316 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -77,8 +77,8 @@ struct Configuration {
   uint64_t globalBase;
   uint64_t initialHeap;
   uint64_t initialMemory;
-  uint64_t maxMemoryGrowth;
   uint64_t maxMemory;
+  bool noGrowableMemory;
   // The table offset at which to place function addresses.  We reserve zero
   // for the null function pointer.  This gets set to 1 for executables and 0
   // for shared libraries (since they always added to a dynamic offset at
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 87afdd223a707a..94b9f4d799f31e 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -541,8 +541,8 @@ static void readConfigs(opt::InputArgList &args) {
   config->globalBase = args::getInteger(args, OPT_global_base, 0);
   config->initialHeap = args::getInteger(args, OPT_initial_heap, 0);
   config->initialMemory = args::getInteger(args, OPT_initial_memory, 0);
-  config->maxMemoryGrowth = args::getInteger(args, OPT_max_memory_growth, -1);
   config->maxMemory = args::getInteger(args, OPT_max_memory, 0);
+  config->noGrowableMemory = args.hasArg(OPT_no_growable_memory);
   config->zStackSize =
       args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
 
diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td
index ed3e014850278a..70b5aadc26c2a0 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -227,12 +227,12 @@ def initial_heap: JJ<"initial-heap=">,
 def initial_memory: JJ<"initial-memory=">,
   HelpText<"Initial size of the linear memory">;
 
-def max_memory_growth: JJ<"max-memory-growth=">,
-  HelpText<"Maximum size of dynamically allocatable linear memory">;
-
 def max_memory: JJ<"max-memory=">,
   HelpText<"Maximum size of the linear memory">;
 
+def no_growable_memory: FF<"no-growable-memory">,
+  HelpText<"Set maximum size of the linear memory to its initial size">;
+
 def no_entry: FF<"no-entry">,
   HelpText<"Do not output any entry point">;
 
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 261d633f11b745..94832a4ca41705 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -473,25 +473,12 @@ void Writer::layoutMemory() {
     WasmSym::heapEnd->setVA(memoryPtr);
   }
 
-  if (config->maxMemory != 0 && config->maxMemoryGrowth != -1) {
+  if (config->maxMemory != 0 && config->noGrowableMemory) {
     // Erroring out here is simpler than defining precedence rules.
-    error("--max-memory-growth and --max-memory are mutually exclusive");
+    error("--max-memory and --no-growable-memory are mutually exclusive");
   }
 
   uint64_t maxMemory = 0;
-  if (config->maxMemoryGrowth != -1) {
-    if (config->maxMemoryGrowth !=
-        alignTo(config->maxMemoryGrowth, WasmPageSize))
-      error("maximum memory growth must be " + Twine(WasmPageSize) +
-            "-byte aligned");
-    uint64_t maxMaxMemoryGrowth = maxMemorySetting - memoryPtr;
-    if (config->maxMemoryGrowth > maxMaxMemoryGrowth)
-      error("maximum memory growth too large, cannot be greater than " +
-            Twine(maxMaxMemoryGrowth));
-
-    maxMemory = memoryPtr + config->maxMemoryGrowth;
-  }
-
   if (config->maxMemory != 0) {
     if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize))
       error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
@@ -502,6 +489,8 @@ void Writer::layoutMemory() {
             Twine(maxMemorySetting));
 
     maxMemory = config->maxMemory;
+  } else if (config->noGrowableMemory) {
+    maxMemory = memoryPtr;
   }
 
   // If no maxMemory config was supplied but we are building with

>From bed9560457cfb98cefd402bd836e15f1a99952c5 Mon Sep 17 00:00:00 2001
From: SingleAccretion <AccretionMail at yandex.ru>
Date: Sun, 25 Feb 2024 12:18:25 +0300
Subject: [PATCH 3/3] Tweak error handling

---
 lld/test/wasm/data-layout.s | 2 +-
 lld/wasm/Driver.cpp         | 5 +++++
 lld/wasm/Writer.cpp         | 5 -----
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/lld/test/wasm/data-layout.s b/lld/test/wasm/data-layout.s
index 7f9da2e5387cac..a68bc032e4840d 100644
--- a/lld/test/wasm/data-layout.s
+++ b/lld/test/wasm/data-layout.s
@@ -117,7 +117,7 @@ local_struct_internal_ptr:
 # RUN:     --no-entry -o %t_max.wasm %t.hello32.o 2>&1 \
 # RUN: | FileCheck %s --check-prefix CHECK-NO-GROWTH-COMPAT-ERROR
 
-# CHECK-NO-GROWTH-COMPAT-ERROR: --max-memory and --no-growable-memory are mutually exclusive
+# CHECK-NO-GROWTH-COMPAT-ERROR: --max-memory is incompatible with --no-growable-memory
 
 # RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry --shared-memory \
 # RUN:     --features=atomics,bulk-memory --initial-memory=131072 \
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 94b9f4d799f31e..df7d4d1cc3d679 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -546,6 +546,11 @@ static void readConfigs(opt::InputArgList &args) {
   config->zStackSize =
       args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
 
+  if (config->maxMemory != 0 && config->noGrowableMemory) {
+    // Erroring out here is simpler than defining precedence rules.
+    error("--max-memory is incompatible with --no-growable-memory");
+  }
+
   // Default value of exportDynamic depends on `-shared`
   config->exportDynamic =
       args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, config->shared);
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 94832a4ca41705..55eff995fb8a16 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -473,11 +473,6 @@ void Writer::layoutMemory() {
     WasmSym::heapEnd->setVA(memoryPtr);
   }
 
-  if (config->maxMemory != 0 && config->noGrowableMemory) {
-    // Erroring out here is simpler than defining precedence rules.
-    error("--max-memory and --no-growable-memory are mutually exclusive");
-  }
-
   uint64_t maxMemory = 0;
   if (config->maxMemory != 0) {
     if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize))



More information about the llvm-commits mailing list