[lld] d4c8a0e - [wasm-ld] Allow importing/exporting the output module's memory with arbitrary names
Dan Gohman via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 31 13:59:54 PDT 2022
Author: Dan Gohman
Date: 2022-10-31T13:59:46-07:00
New Revision: d4c8a0edca51d83b084291960eea6664b9f56327
URL: https://github.com/llvm/llvm-project/commit/d4c8a0edca51d83b084291960eea6664b9f56327
DIFF: https://github.com/llvm/llvm-project/commit/d4c8a0edca51d83b084291960eea6664b9f56327.diff
LOG: [wasm-ld] Allow importing/exporting the output module's memory with arbitrary names
This adds an `--export-memory` option to wasm-ld which allows passing
a name to give to the exported memory, and extends `--import-memory` to
allow passing a <module>,<name> pair specifying where the memory should
be imported from.
This is based on https://reviews.llvm.org/D131376, with the main
difference being that it only supports exporting memory by one name.
Differential Revision: https://reviews.llvm.org/D135898
Added:
lld/test/wasm/memory-naming.test
Modified:
lld/wasm/Config.h
lld/wasm/Driver.cpp
lld/wasm/Options.td
lld/wasm/Symbols.cpp
lld/wasm/Symbols.h
lld/wasm/SyntheticSections.cpp
lld/wasm/SyntheticSections.h
lld/wasm/Writer.cpp
Removed:
################################################################################
diff --git a/lld/test/wasm/memory-naming.test b/lld/test/wasm/memory-naming.test
new file mode 100644
index 0000000000000..b4aabaeeac357
--- /dev/null
+++ b/lld/test/wasm/memory-naming.test
@@ -0,0 +1,88 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/start.s -o %t.start.o
+# RUN: wasm-ld --export-memory=foo -o %t.wasm %t.start.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Verify that the --export-memory=<name> option changes the exported name of the module's memory
+
+# CHECK: - Type: EXPORT
+# CHECK-NEXT: Exports:
+# CHECK-NEXT: - Name: foo
+# CHECK-NEXT: Kind: MEMORY
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: - Name: _start
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: - Type:
+
+# RUN:wasm-ld --export-memory --export-memory -o %t.unnamed.wasm %t.start.o
+# RUN: obj2yaml %t.unnamed.wasm | FileCheck -check-prefix=CHECK-UNNAMED %s
+
+# Verify that the --export-memory option without a parameter exports the memory
+# as "memory"
+
+# CHECK-UNNAMED: - Type: EXPORT
+# CHECK-UNNAMED-NEXT: Exports:
+# CHECK-UNNAMED-NEXT: - Name: memory
+# CHECK-UNNAMED-NEXT: Kind: MEMORY
+# CHECK-UNNAMED-NEXT: Index: 0
+# CHECK-UNNAMED-NEXT: - Name: _start
+# CHECK-UNNAMED-NEXT: Kind: FUNCTION
+# CHECK-UNNAMED-NEXT: Index: 0
+# CHECK-UNNAMED-NEXT: - Type:
+
+# RUN:wasm-ld --export-memory=foo --export-memory=foo -o %t.duplicate.wasm %t.start.o
+# RUN: obj2yaml %t.duplicate.wasm | FileCheck -check-prefix=CHECK-DUPLICATE %s
+
+# Verify that passing --export-memory with the same name twice works
+
+# CHECK-DUPLICATE: - Type: EXPORT
+# CHECK-DUPLICATE-NEXT: Exports:
+# CHECK-DUPLICATE-NEXT: - Name: foo
+# CHECK-DUPLICATE-NEXT: Kind: MEMORY
+# CHECK-DUPLICATE-NEXT: Index: 0
+# CHECK-DUPLICATE-NEXT: - Name: _start
+# CHECK-DUPLICATE-NEXT: Kind: FUNCTION
+# CHECK-DUPLICATE-NEXT: Index: 0
+# CHECK-DUPLICATE-NEXT: - Type:
+
+# RUN:wasm-ld --import-memory=foo,bar -o %t.import.wasm %t.start.o
+# RUN: obj2yaml %t.import.wasm | FileCheck -check-prefix=CHECK-IMPORT %s
+
+# Verify that memory imports can be renamed, and that no memory is exported by
+# default when memory is being imported
+
+# CHECK-IMPORT: - Type: IMPORT
+# CHECK-IMPORT-NEXT: Imports:
+# CHECK-IMPORT-NEXT: - Module: foo
+# CHECK-IMPORT-NEXT: Field: bar
+# CHECK-IMPORT-NEXT: Kind: MEMORY
+# CHECK-IMPORT-NEXT: Memory:
+# CHECK-IMPORT-NEXT: Minimum: 0x2
+# CHECK-IMPORT: - Type: EXPORT
+# CHECK-IMPORT-NEXT: Exports:
+# CHECK-IMPORT-NEXT: - Name: _start
+# CHECK-IMPORT-NEXT: Kind: FUNCTION
+# CHECK-IMPORT-NEXT: Index: 0
+# CHECK-IMPORT-NEXT: - Type:
+
+# RUN:wasm-ld --import-memory=foo,bar --export-memory=qux -o %t.both.wasm %t.start.o
+# RUN: obj2yaml %t.both.wasm | FileCheck -check-prefix=CHECK-BOTH %s
+
+# Verify that memory can be both imported and exported from a module
+
+# CHECK-BOTH: - Type: IMPORT
+# CHECK-BOTH-NEXT: Imports:
+# CHECK-BOTH-NEXT: - Module: foo
+# CHECK-BOTH-NEXT: Field: bar
+# CHECK-BOTH-NEXT: Kind: MEMORY
+# CHECK-BOTH-NEXT: Memory:
+# CHECK-BOTH-NEXT: Minimum: 0x2
+# CHECK-BOTH: - Type: EXPORT
+# CHECK-BOTH-NEXT: Exports:
+# CHECK-BOTH-NEXT: - Name: qux
+# CHECK-BOTH-NEXT: Kind: MEMORY
+# CHECK-BOTH-NEXT: Index: 0
+# CHECK-BOTH-NEXT: - Name: _start
+# CHECK-BOTH-NEXT: Kind: FUNCTION
+# CHECK-BOTH-NEXT: Index: 0
+# CHECK-BOTH-NEXT: - Type:
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index 35171b5afd8f1..71d6bd99f649b 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -39,7 +39,8 @@ struct Configuration {
bool extendedConst;
bool growableTable;
bool gcSections;
- bool importMemory;
+ llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> memoryImport;
+ llvm::Optional<llvm::StringRef> memoryExport;
bool sharedMemory;
bool importTable;
bool importUndefined;
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index b0d37b9fc3a4a..68e217f7e9877 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -393,7 +393,27 @@ static void readConfigs(opt::InputArgList &args) {
config->exportAll = args.hasArg(OPT_export_all);
config->exportTable = args.hasArg(OPT_export_table);
config->growableTable = args.hasArg(OPT_growable_table);
- config->importMemory = args.hasArg(OPT_import_memory);
+
+ if (args.hasArg(OPT_import_memory_with_name)) {
+ config->memoryImport =
+ args.getLastArgValue(OPT_import_memory_with_name).split(",");
+ } else if (args.hasArg(OPT_import_memory)) {
+ config->memoryImport =
+ std::pair<llvm::StringRef, llvm::StringRef>(defaultModule, memoryName);
+ } else {
+ config->memoryImport =
+ llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>();
+ }
+
+ if (args.hasArg(OPT_export_memory_with_name)) {
+ config->memoryExport =
+ args.getLastArgValue(OPT_export_memory_with_name);
+ } else if (args.hasArg(OPT_export_memory)) {
+ config->memoryExport = memoryName;
+ } else {
+ config->memoryExport = llvm::Optional<llvm::StringRef>();
+ }
+
config->sharedMemory = args.hasArg(OPT_shared_memory);
config->importTable = args.hasArg(OPT_import_table);
config->importUndefined = args.hasArg(OPT_import_undefined);
@@ -510,9 +530,21 @@ static void setConfigs() {
}
if (config->shared) {
- config->importMemory = true;
+ if (config->memoryExport.hasValue()) {
+ error("--export-memory is incompatible with --shared");
+ }
+ if (!config->memoryImport.hasValue()) {
+ config->memoryImport =
+ std::pair<llvm::StringRef, llvm::StringRef>(defaultModule, memoryName);
+ }
config->importUndefined = true;
}
+
+ // If neither export-memory nor import-memory is specified, default to
+ // exporting memory under its default name.
+ if (!config->memoryExport.hasValue() && !config->memoryImport.hasValue()) {
+ config->memoryExport = memoryName;
+ }
}
// Some command line options or some combinations of them are not allowed.
diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td
index ec452a38ae53e..2871ae6d576be 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -189,7 +189,15 @@ def global_base: JJ<"global-base=">,
HelpText<"Where to start to place global data">;
def import_memory: FF<"import-memory">,
- HelpText<"Import memory from the environment">;
+ HelpText<"Import the module's memory from the default module of \"env\" with the name \"memory\".">;
+def import_memory_with_name: JJ<"import-memory=">,
+ HelpText<"Import the module's memory from the passed module with the passed name.">,
+ MetaVarName<"<module>,<name>">;
+
+def export_memory: FF<"export-memory">,
+ HelpText<"Export the module's memory with the default name of \"memory\"">;
+def export_memory_with_name: JJ<"export-memory=">,
+ HelpText<"Export the module's memory with the passed name">;
def shared_memory: FF<"shared-memory">,
HelpText<"Use shared linear memory">;
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index c6f6e04ad4c8a..5ef92dde7cc58 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -457,6 +457,7 @@ void printTraceSymbol(Symbol *sym) {
const char *defaultModule = "env";
const char *functionTableName = "__indirect_function_table";
+const char *memoryName = "memory";
} // namespace wasm
} // namespace lld
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index ee6c5db181a1c..ac0e42a2496ba 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -26,6 +26,9 @@ extern const char *defaultModule;
// The name under which to import or export the wasm table.
extern const char *functionTableName;
+// The name under which to import or export the wasm memory.
+extern const char *memoryName;
+
using llvm::wasm::WasmSymbolType;
class InputFile;
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index c39d86cee87e4..3be2beb735787 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -162,7 +162,7 @@ void TypeSection::writeBody() {
uint32_t ImportSection::getNumImports() const {
assert(isSealed);
uint32_t numImports = importedSymbols.size() + gotSymbols.size();
- if (config->importMemory)
+ if (config->memoryImport.hasValue())
++numImports;
return numImports;
}
@@ -234,10 +234,10 @@ void ImportSection::writeBody() {
bool is64 = config->is64.value_or(false);
- if (config->importMemory) {
+ if (config->memoryImport) {
WasmImport import;
- import.Module = defaultModule;
- import.Field = "memory";
+ import.Module = config->memoryImport.getValue().first;
+ import.Field = config->memoryImport.getValue().second;
import.Kind = WASM_EXTERNAL_MEMORY;
import.Memory.Flags = 0;
import.Memory.Minimum = out.memorySec->numMemoryPages;
diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h
index 06579054b6300..fe2d3879b6e2d 100644
--- a/lld/wasm/SyntheticSections.h
+++ b/lld/wasm/SyntheticSections.h
@@ -230,7 +230,7 @@ class MemorySection : public SyntheticSection {
public:
MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}
- bool isNeeded() const override { return !config->importMemory; }
+ bool isNeeded() const override { return !config->memoryImport.hasValue(); }
void writeBody() override;
uint64_t numMemoryPages = 0;
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 9937c009f62f0..bd01474353338 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -577,7 +577,7 @@ void Writer::populateTargetFeatures() {
// memory is not being imported then we can assume its zero initialized.
// In the case the memory is imported, and we can use the memory.fill
// instruction, then we can also avoid including the segments.
- if (config->importMemory && !allowed.count("bulk-memory"))
+ if (config->memoryImport.hasValue() && !allowed.count("bulk-memory"))
config->emitBssSegments = true;
if (allowed.count("extended-const"))
@@ -671,9 +671,10 @@ void Writer::calculateExports() {
if (config->relocatable)
return;
- if (!config->relocatable && !config->importMemory)
+ if (!config->relocatable && config->memoryExport.hasValue()) {
out.exportSec->exports.push_back(
- WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0});
+ WasmExport{*config->memoryExport, WASM_EXTERNAL_MEMORY, 0});
+ }
unsigned globalIndex =
out.importSec->getNumImportedGlobals() + out.globalSec->numGlobals();
@@ -1007,7 +1008,7 @@ static void createFunction(DefinedFunction *func, StringRef bodyContent) {
bool Writer::needsPassiveInitialization(const OutputSegment *segment) {
// If bulk memory features is supported then we can perform bss initialization
// (via memory.fill) during `__wasm_init_memory`.
- if (config->importMemory && !segment->requiredInBinary())
+ if (config->memoryImport.hasValue() && !segment->requiredInBinary())
return true;
return segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE;
}
More information about the llvm-commits
mailing list