Skip to content

Commit 729ea41

Browse files
authored
Add bulk-memory-opt feature and ignore call-indirect-overlong (#7139)
LLVM recently split the bulk-memory-opt feature out from bulk-memory, containing just memory.copy and memory.fill. This change follows that, making bulk-memory-opt also enabled when all of bulk-memory is enabled. It also introduces call-indirect-overlong following LLVM, but ignores it, since Binaryen has always allowed the encoding (i.e. command line flags enabling or disabling the feature are accepted but ignored).
1 parent 3f82ffc commit 729ea41

24 files changed

+225
-25
lines changed

src/passes/LLVMMemoryCopyFillLowering.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct LLVMMemoryCopyFillLowering
4949
}
5050

5151
void run(Module* module) override {
52-
if (!module->features.hasBulkMemory()) {
52+
if (!module->features.hasBulkMemoryOpt()) {
5353
return;
5454
}
5555
if (module->features.hasMemory64() || module->features.hasMultiMemory()) {
@@ -108,7 +108,7 @@ struct LLVMMemoryCopyFillLowering
108108
} else {
109109
module->removeFunction(memFillFuncName);
110110
}
111-
module->features.disable(FeatureSet::BulkMemory);
111+
module->features.setBulkMemoryOpt(false);
112112
}
113113

114114
void createMemoryCopyFunc(Module* module) {

src/passes/OptimizeInstructions.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,7 @@ struct OptimizeInstructions
12751275
if (curr->type == Type::unreachable) {
12761276
return;
12771277
}
1278-
assert(getModule()->features.hasBulkMemory());
1278+
assert(getModule()->features.hasBulkMemoryOpt());
12791279
if (auto* ret = optimizeMemoryCopy(curr)) {
12801280
return replaceCurrent(ret);
12811281
}
@@ -1285,7 +1285,7 @@ struct OptimizeInstructions
12851285
if (curr->type == Type::unreachable) {
12861286
return;
12871287
}
1288-
assert(getModule()->features.hasBulkMemory());
1288+
assert(getModule()->features.hasBulkMemoryOpt());
12891289
if (auto* ret = optimizeMemoryFill(curr)) {
12901290
return replaceCurrent(ret);
12911291
}

src/tools/tool-options.h

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,16 @@ struct ToolOptions : public Options {
8282
.addFeature(FeatureSet::MutableGlobals, "mutable globals")
8383
.addFeature(FeatureSet::TruncSat, "nontrapping float-to-int operations")
8484
.addFeature(FeatureSet::SIMD, "SIMD operations and types")
85-
.addFeature(FeatureSet::BulkMemory, "bulk memory operations")
85+
.addFeature(FeatureSet::BulkMemory,
86+
"bulk memory operations",
87+
FeatureSet(FeatureSet::BulkMemoryOpt))
88+
.addFeature(FeatureSet::BulkMemoryOpt,
89+
"memory.copy and memory.fill",
90+
FeatureSet::None,
91+
FeatureSet(FeatureSet::BulkMemory))
92+
.addFeature(FeatureSet::CallIndirectOverlong,
93+
"LEB encoding of call-indirect (Ignored for compatibility as "
94+
"it has no effect on Binaryen)")
8695
.addFeature(FeatureSet::ExceptionHandling,
8796
"exception handling operations")
8897
.addFeature(FeatureSet::TailCall, "tail call operations")
@@ -200,26 +209,28 @@ struct ToolOptions : public Options {
200209
}
201210

202211
ToolOptions& addFeature(FeatureSet::Feature feature,
203-
const std::string& description) {
212+
const std::string& description,
213+
FeatureSet impliedEnable = FeatureSet::None,
214+
FeatureSet impliedDisable = FeatureSet::None) {
204215
(*this)
205216
.add(std::string("--enable-") + FeatureSet::toString(feature),
206217
"",
207218
std::string("Enable ") + description,
208219
ToolOptionsCategory,
209220
Arguments::Zero,
210-
[this, feature](Options*, const std::string&) {
211-
enabledFeatures.set(feature, true);
212-
disabledFeatures.set(feature, false);
221+
[this, feature, impliedEnable](Options*, const std::string&) {
222+
enabledFeatures.set(feature | impliedEnable, true);
223+
disabledFeatures.set(feature | impliedEnable, false);
213224
})
214225

215226
.add(std::string("--disable-") + FeatureSet::toString(feature),
216227
"",
217228
std::string("Disable ") + description,
218229
ToolOptionsCategory,
219230
Arguments::Zero,
220-
[this, feature](Options*, const std::string&) {
221-
enabledFeatures.set(feature, false);
222-
disabledFeatures.set(feature, true);
231+
[this, feature, impliedDisable](Options*, const std::string&) {
232+
enabledFeatures.set(feature | impliedDisable, false);
233+
disabledFeatures.set(feature | impliedDisable, true);
223234
});
224235
return *this;
225236
}

src/wasm-binary.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,8 @@ extern const char* MultiMemoryFeature;
396396
extern const char* TypedContinuationsFeature;
397397
extern const char* SharedEverythingFeature;
398398
extern const char* FP16Feature;
399+
extern const char* BulkMemoryOptFeature;
400+
extern const char* CallIndirectOverlongFeature;
399401

400402
enum Subsection {
401403
NameModule = 0,

src/wasm-features.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ namespace wasm {
2727

2828
struct FeatureSet {
2929
enum Feature : uint32_t {
30+
// These features are intended to those documented in tool-conventions:
31+
// https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md#target-features-section
3032
None = 0,
3133
Atomics = 1 << 0,
3234
MutableGlobals = 1 << 1,
@@ -47,11 +49,16 @@ struct FeatureSet {
4749
TypedContinuations = 1 << 16,
4850
SharedEverything = 1 << 17,
4951
FP16 = 1 << 18,
52+
BulkMemoryOpt = 1 << 19, // Just the memory.copy and fill operations
53+
// This features is a no-op for compatibility. Having it in this list means
54+
// that we can automatically generate tool flags that set it, but otherwise
55+
// it does nothing. Binaryen always accepts LEB call-indirect encodings.
56+
CallIndirectOverlong = 1 << 20,
5057
MVP = None,
5158
// Keep in sync with llvm default features:
5259
// https://github.com/llvm/llvm-project/blob/c7576cb89d6c95f03968076e902d3adfd1996577/clang/lib/Basic/Targets/WebAssembly.cpp#L150-L153
5360
Default = SignExt | MutableGlobals,
54-
All = (1 << 19) - 1,
61+
All = (1 << 21) - 1,
5562
};
5663

5764
static std::string toString(Feature f) {
@@ -94,6 +101,10 @@ struct FeatureSet {
94101
return "shared-everything";
95102
case FP16:
96103
return "fp16";
104+
case BulkMemoryOpt:
105+
return "bulk-memory-opt";
106+
case CallIndirectOverlong:
107+
return "call-indirect-overlong";
97108
default:
98109
WASM_UNREACHABLE("unexpected feature");
99110
}
@@ -145,6 +156,11 @@ struct FeatureSet {
145156
return (features & SharedEverything) != 0;
146157
}
147158
bool hasFP16() const { return (features & FP16) != 0; }
159+
bool hasBulkMemoryOpt() const {
160+
bool has = (features & BulkMemoryOpt) != 0;
161+
assert(has || !hasBulkMemory());
162+
return has;
163+
}
148164
bool hasAll() const { return (features & All) != 0; }
149165

150166
void set(FeatureSet f, bool v = true) {
@@ -169,6 +185,7 @@ struct FeatureSet {
169185
void setTypedContinuations(bool v = true) { set(TypedContinuations, v); }
170186
void setSharedEverything(bool v = true) { set(SharedEverything, v); }
171187
void setFP16(bool v = true) { set(FP16, v); }
188+
void setBulkMemoryOpt(bool v = true) { set(BulkMemoryOpt, v); }
172189
void setMVP() { features = MVP; }
173190
void setAll() { features = All; }
174191

src/wasm/wasm-binary.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,10 @@ void WasmBinaryWriter::writeFeaturesSection() {
13541354
return BinaryConsts::CustomSections::SharedEverythingFeature;
13551355
case FeatureSet::FP16:
13561356
return BinaryConsts::CustomSections::FP16Feature;
1357+
case FeatureSet::BulkMemoryOpt:
1358+
return BinaryConsts::CustomSections::BulkMemoryOptFeature;
1359+
case FeatureSet::CallIndirectOverlong:
1360+
return BinaryConsts::CustomSections::CallIndirectOverlongFeature;
13571361
case FeatureSet::None:
13581362
case FeatureSet::Default:
13591363
case FeatureSet::All:
@@ -4790,6 +4794,12 @@ void WasmBinaryReader::readFeatures(size_t payloadLen) {
47904794
feature = FeatureSet::Atomics;
47914795
} else if (name == BinaryConsts::CustomSections::BulkMemoryFeature) {
47924796
feature = FeatureSet::BulkMemory;
4797+
if (used) {
4798+
// For backward compatibility, enable this dependent feature.
4799+
feature |= FeatureSet::BulkMemoryOpt;
4800+
}
4801+
} else if (name == BinaryConsts::CustomSections::BulkMemoryOptFeature) {
4802+
feature = FeatureSet::BulkMemoryOpt;
47934803
} else if (name == BinaryConsts::CustomSections::ExceptionHandlingFeature) {
47944804
feature = FeatureSet::ExceptionHandling;
47954805
} else if (name == BinaryConsts::CustomSections::MutableGlobalsFeature) {

src/wasm/wasm-validator.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,10 +1526,10 @@ void FunctionValidator::visitDataDrop(DataDrop* curr) {
15261526
}
15271527

15281528
void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) {
1529-
shouldBeTrue(
1530-
getModule()->features.hasBulkMemory(),
1531-
curr,
1532-
"Bulk memory operations require bulk memory [--enable-bulk-memory]");
1529+
shouldBeTrue(getModule()->features.hasBulkMemoryOpt(),
1530+
curr,
1531+
"memory.copy operations require bulk memory operations "
1532+
"[--enable-bulk-memory-opt]");
15331533
shouldBeEqualOrFirstIsUnreachable(
15341534
curr->type, Type(Type::none), curr, "memory.copy must have type none");
15351535
auto* destMemory = getModule()->getMemoryOrNull(curr->destMemory);
@@ -1561,9 +1561,9 @@ void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) {
15611561
void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
15621562
auto* memory = getModule()->getMemoryOrNull(curr->memory);
15631563
shouldBeTrue(
1564-
getModule()->features.hasBulkMemory(),
1564+
getModule()->features.hasBulkMemoryOpt(),
15651565
curr,
1566-
"Bulk memory operations require bulk memory [--enable-bulk-memory]");
1566+
"memory.fill operations require bulk memory [--enable-bulk-memory-opt]");
15671567
shouldBeEqualOrFirstIsUnreachable(
15681568
curr->type, Type(Type::none), curr, "memory.fill must have type none");
15691569
shouldBeEqualOrFirstIsUnreachable(

src/wasm/wasm.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ const char* MultiMemoryFeature = "multimemory";
5757
const char* TypedContinuationsFeature = "typed-continuations";
5858
const char* SharedEverythingFeature = "shared-everything";
5959
const char* FP16Feature = "fp16";
60+
const char* BulkMemoryOptFeature = "bulk-memory-opt";
61+
const char* CallIndirectOverlongFeature = "call-indirect-overlong";
6062
} // namespace CustomSections
6163
} // namespace BinaryConsts
6264

test/binaryen.js/kitchen-sink.js.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Features.RelaxedSIMD: 4096
3333
Features.ExtendedConst: 8192
3434
Features.Strings: 16384
3535
Features.MultiMemory: 32768
36-
Features.All: 524287
36+
Features.All: 2097151
3737
InvalidId: 0
3838
BlockId: 1
3939
IfId: 2

test/example/c-api-kitchen-sink.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ BinaryenFeatureMemory64: 2048
4747
BinaryenFeatureRelaxedSIMD: 4096
4848
BinaryenFeatureExtendedConst: 8192
4949
BinaryenFeatureStrings: 16384
50-
BinaryenFeatureAll: 524287
50+
BinaryenFeatureAll: 2097151
5151
(f32.neg
5252
(f32.const -33.61199951171875)
5353
)

0 commit comments

Comments
 (0)