Skip to content

Commit bea291a

Browse files
tlivelyarichardson
authored andcommitted
[WebAssembly] Disallow 'shared-mem' rather than 'atomics'
Summary: The WebAssembly backend automatically lowers atomic operations and TLS to nonatomic operations and non-TLS data when either are present and the atomics or bulk-memory features are not present, respectively. The resulting object is no longer thread-safe, so the linker has to be told not to allow it to be linked into a module with shared memory. This was previously done by disallowing the 'atomics' feature, which prevented any objct with its atomic operations or TLS removed from being linked with any object containing atomics or TLS, and therefore preventing it from being linked into a module with shared memory since shared memory requires atomics. However, as of WebAssembly/threads#144, the validation rules are relaxed to allow atomic operations to validate with unshared memories, which makes it perfectly safe to link an object with stripped atomics and TLS with another object that still contains TLS and atomics as long as the resulting module has an unshared memory. To allow this kind of link, this patch disallows a pseudo-feature 'shared-mem' rather than 'atomics' to communicate to the linker that the object is not thread-safe. This means that the 'atomics' feature is available to accurately reflect whether or not an object has atomics enabled. As a drive-by tweak, this change also requires that bulk-memory be enabled in addition to atomics in order to use shared memory. This is because initializing shared memories requires bulk-memory operations. Reviewers: aheejin, sbc100 Subscribers: dschuff, jgravelle-google, hiraditya, sunfish, jfb, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D79542
2 parents 2dd0652 + a1ae956 commit bea291a

File tree

5 files changed

+45
-35
lines changed

5 files changed

+45
-35
lines changed

lld/test/wasm/shared-memory-no-atomics.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ Sections:
4949
Name: target_features
5050
Features:
5151
- Prefix: DISALLOWED
52-
Name: "atomics"
52+
Name: "shared-mem"
5353
...
5454

5555
# NO-SHARED: - Type: MEMORY
5656
# NO-SHARED-NEXT: Memories:
5757
# NO-SHARED-NEXT: - Initial: 0x00000002
5858
# NO-SHARED-NOT: Maximum:
5959

60-
# SHARED: 'atomics' feature is disallowed by {{.*}}shared-memory-no-atomics.yaml.tmp1.o, so --shared-memory must not be used{{$}}
60+
# SHARED: --shared-memory is disallowed by {{.*}}shared-memory-no-atomics.yaml.tmp1.o because it was not compiled with 'atomics' or 'bulk-memory' features.

lld/wasm/Writer.cpp

+17-14
Original file line numberDiff line numberDiff line change
@@ -441,21 +441,24 @@ void Writer::populateTargetFeatures() {
441441
if (!config->checkFeatures)
442442
return;
443443

444-
if (disallowed.count("atomics") && config->sharedMemory)
445-
error("'atomics' feature is disallowed by " + disallowed["atomics"] +
446-
", so --shared-memory must not be used");
447-
448-
if (!allowed.count("atomics") && config->sharedMemory)
449-
error("'atomics' feature must be used in order to use shared "
450-
"memory");
451-
452-
if (!allowed.count("bulk-memory") && config->sharedMemory)
453-
error("'bulk-memory' feature must be used in order to use shared "
454-
"memory");
444+
if (config->sharedMemory) {
445+
if (disallowed.count("shared-mem"))
446+
error("--shared-memory is disallowed by " + disallowed["shared-mem"] +
447+
" because it was not compiled with 'atomics' or 'bulk-memory' "
448+
"features.");
449+
450+
for (auto feature : {"atomics", "bulk-memory"})
451+
if (!allowed.count(feature))
452+
error(StringRef("'") + feature +
453+
"' feature must be used in order to use shared memory");
454+
}
455455

456-
if (!allowed.count("bulk-memory") && tlsUsed)
457-
error("'bulk-memory' feature must be used in order to use thread-local "
458-
"storage");
456+
if (tlsUsed) {
457+
for (auto feature : {"atomics", "bulk-memory"})
458+
if (!allowed.count(feature))
459+
error(StringRef("'") + feature +
460+
"' feature must be used in order to use thread-local storage");
461+
}
459462

460463
// Validate that used features are allowed in output
461464
if (!inferFeatures) {

llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -230,20 +230,20 @@ void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
230230
void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {
231231
struct FeatureEntry {
232232
uint8_t Prefix;
233-
StringRef Name;
233+
std::string Name;
234234
};
235235

236236
// Read target features and linkage policies from module metadata
237237
SmallVector<FeatureEntry, 4> EmittedFeatures;
238-
for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
239-
std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
238+
auto EmitFeature = [&](std::string Feature) {
239+
std::string MDKey = (StringRef("wasm-feature-") + Feature).str();
240240
Metadata *Policy = M.getModuleFlag(MDKey);
241241
if (Policy == nullptr)
242-
continue;
242+
return;
243243

244244
FeatureEntry Entry;
245245
Entry.Prefix = 0;
246-
Entry.Name = KV.Key;
246+
Entry.Name = Feature;
247247

248248
if (auto *MD = cast<ConstantAsMetadata>(Policy))
249249
if (auto *I = cast<ConstantInt>(MD->getValue()))
@@ -253,10 +253,16 @@ void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) {
253253
if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED &&
254254
Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED &&
255255
Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED)
256-
continue;
256+
return;
257257

258258
EmittedFeatures.push_back(Entry);
259+
};
260+
261+
for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
262+
EmitFeature(KV.Key);
259263
}
264+
// This pseudo-feature tells the linker whether shared memory would be safe
265+
EmitFeature("shared-mem");
260266

261267
if (EmittedFeatures.size() == 0)
262268
return;

llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp

+12-11
Original file line numberDiff line numberDiff line change
@@ -273,21 +273,22 @@ class CoalesceFeaturesAndStripAtomics final : public ModulePass {
273273

274274
void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) {
275275
for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
276-
std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
277-
if (KV.Value == WebAssembly::FeatureAtomics && Stripped) {
278-
// "atomics" is special: code compiled without atomics may have had its
279-
// atomics lowered to nonatomic operations. In that case, atomics is
280-
// disallowed to prevent unsafe linking with atomics-enabled objects.
281-
assert(!Features[WebAssembly::FeatureAtomics] ||
282-
!Features[WebAssembly::FeatureBulkMemory]);
283-
M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
284-
wasm::WASM_FEATURE_PREFIX_DISALLOWED);
285-
} else if (Features[KV.Value]) {
286-
// Otherwise features are marked Used or not mentioned
276+
if (Features[KV.Value]) {
277+
// Mark features as used
278+
std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
287279
M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
288280
wasm::WASM_FEATURE_PREFIX_USED);
289281
}
290282
}
283+
// Code compiled without atomics or bulk-memory may have had its atomics or
284+
// thread-local data lowered to nonatomic operations or non-thread-local
285+
// data. In that case, we mark the pseudo-feature "shared-mem" as disallowed
286+
// to tell the linker that it would be unsafe to allow this code ot be used
287+
// in a module with shared memory.
288+
if (Stripped) {
289+
M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem",
290+
wasm::WASM_FEATURE_PREFIX_DISALLOWED);
291+
}
291292
}
292293
};
293294
char CoalesceFeaturesAndStripAtomics::ID = 0;

llvm/test/CodeGen/WebAssembly/target-features-tls.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ target triple = "wasm32-unknown-unknown"
1313
; NO-BULK-MEM-LABEL: .custom_section.target_features,"",@
1414
; NO-BULK-MEM-NEXT: .int8 1
1515
; NO-BULK-MEM-NEXT: .int8 45
16-
; NO-BULK-MEM-NEXT: .int8 7
17-
; NO-BULK-MEM-NEXT: .ascii "atomics"
16+
; NO-BULK-MEM-NEXT: .int8 10
17+
; NO-BULK-MEM-NEXT: .ascii "shared-mem"
1818
; NO-BULK-MEM-NEXT: .bss.foo,"",@
1919

2020
; +bulk-memory

0 commit comments

Comments
 (0)